package com.bigknow.appstore.proxy.server.impl;

import com.bigknow.appstore.proxy.cache.ICacheManager;
import com.bigknow.appstore.proxy.entity.ProxyResourceMeta;
import com.bigknow.appstore.proxy.handler.base.BaseInboundHandler;
import com.bigknow.appstore.proxy.log.ILogWriter;
import com.bigknow.appstore.proxy.server.IChannelClientToProxy;
import com.bigknow.appstore.proxy.server.IChannelProxyToServer;
import com.bigknow.appstore.proxy.server.IProxyServer;
import com.bigknow.appstore.proxy.util.HandlerVariables;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpMessage;
import io.netty.handler.codec.http.FullHttpRequest;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.StampedLock;

/**
 * 默认的httpchannelClientToProxy
 * Created by chaos on 2016/9/13.
 */
@ChannelHandler.Sharable
public class HttpChannelClientToProxy extends BaseInboundHandler implements IChannelClientToProxy {

    private StampedLock lock = new StampedLock();

    private Map<String, IChannelProxyToServer> proxyToServerConnectionsMap = new ConcurrentHashMap<>();

    public HttpChannelClientToProxy(IProxyServer proxyServer, ICacheManager cacheManager, ILogWriter logWriter) {
        super(proxyServer, cacheManager, logWriter);
    }

    @Override
    public void read(ChannelHandlerContext ctx, FullHttpMessage msg) throws Exception {
        //如果 proxyResourceMeta 为空就不应该走到这里
        ProxyResourceMeta proxyResourceMeta = getCurrentRequestVo().getResourceMeta();
        String targetIp = proxyResourceMeta.getSourceHost();
        int targetPort = proxyResourceMeta.getSourcePort();
        if (targetIp == null || targetPort == 0) {
            closeConnection(ctx.channel());
        }

        //一个proxy的clientchannel会针对每一个ip 和 端口创建一个连接
        String cid = ctx.channel().id().asLongText() + targetIp + targetPort;
        long stamp = lock.writeLock();
        try {
            IChannelProxyToServer ps = proxyToServerConnectionsMap.get(cid);
            setRequestVoForProxyToServerResponse(ctx.channel().id().asLongText());
            if (ps != null && ps.isActive()) {
                logger.info("id [" + cid + "]已建立连接，采用已有连接进行数据传递！");
                ps.write((FullHttpRequest) msg);
            } else {
                if (ps != null) ps.disConnect();
                logger.info("尝试创建新连接！");
                proxyToServerConnectionsMap.put(cid, new HttpChannelProxyToServer(
                        this.proxyServer,
                        this.cacheManager,
                        this.writer,
                        ctx.channel(),
                        targetIp,
                        targetPort,
                        (FullHttpRequest) msg));
            }
        } finally {
            lock.unlockWrite(stamp);
        }
    }

    @Override
    public void closeAllProxyToServerConnection() {
        proxyToServerConnectionsMap.values().forEach(channelProxyToServer -> {
            channelProxyToServer.disConnect();
        });
    }

    private void setRequestVoForProxyToServerResponse(String channelId){
        HandlerVariables.requestVoForCurrentResponse.put(channelId
                , HandlerVariables.currentRequestVoLocal.get());
    }
}
